package com.kcwl.idea.plugins.gateway.handler;

import com.kcwl.idea.plugins.base.constants.DocumentTags;
import com.kcwl.idea.plugins.base.utils.PsiDocCommentUtils;
import com.kcwl.idea.plugins.base.utils.PsiSwaggerUtils;
import com.kcwl.idea.plugins.base.utils.PsiAnnotationMemberValueUtil;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.psi.PsiAnnotation;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.javadoc.PsiDocComment;
import com.intellij.psi.javadoc.PsiDocToken;
import org.apache.commons.lang3.StringUtils;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

import static org.apache.commons.lang3.StringUtils.trim;

public class ControllerInfoUtil {
    protected static final String REQUEST_MAPPING = "org.springframework.web.bind.annotation.RequestMapping";

    public static String getApiPath(AnActionEvent actionEvent) {
        PsiMethod method = method(actionEvent);
        String url = url(classAnnotation(method), methodAnnotation(method));
        return url;
    }

    /**
     * 获取接口概述
     */
    public static String getApiSummary(AnActionEvent actionEvent) {
        PsiMethod psiMethod = method(actionEvent);
        // 优先级: swagger注解@ApiOperation > 文档注释标记@description >  文档注释第一行
        String summary = PsiSwaggerUtils.getApiSummary(psiMethod);

        PsiDocComment comment = psiMethod.getDocComment();
        if (comment != null) {
            if (StringUtils.isEmpty(summary)) {
                String[] tags = {DocumentTags.Description, DocumentTags.DescriptionYapiUpload};
                for (String tag : tags) {
                    summary = PsiDocCommentUtils.getDocCommentTagText(psiMethod, tag);
                    if (StringUtils.isNotEmpty(summary)) {
                        break;
                    }
                }
            }

            if (StringUtils.isEmpty(summary)) {
                summary = Arrays.stream(comment.getDescriptionElements())
                        .filter(o -> o instanceof PsiDocToken)
                        .map(PsiElement::getText)
                        .findFirst()
                        .map(String::trim)
                        .orElse(null);
            }
        }
        return trim(summary);
    }



    private static PsiMethod method(AnActionEvent e) {
        DataContext dataContext = e.getDataContext();
        // 肯定是PsiMethod
        return (PsiMethod) CommonDataKeys.PSI_ELEMENT.getData(dataContext);
    }

    private static PsiAnnotation classAnnotation(PsiMethod method) {
        return AnnotationUtil.findAnnotation(method.getContainingClass(), REQUEST_MAPPING);
    }

    private static PsiAnnotation methodAnnotation(PsiMethod method) {
        return AnnotationUtil.findAnnotations(method, getMappings().keySet())[0];
    }

    private static Map<String, String> getMappings() {
        Map<String, String> mappings = new HashMap<>();
        mappings.put("org.springframework.web.bind.annotation.GetMapping", "GET");
        mappings.put("org.springframework.web.bind.annotation.PostMapping", "POST");
        mappings.put("org.springframework.web.bind.annotation.PutMapping", "PUT");
        mappings.put("org.springframework.web.bind.annotation.DeleteMapping", "DELETE");
        mappings.put("org.springframework.web.bind.annotation.PatchMapping", "PATCH");
        // requestMapping
        mappings.put(REQUEST_MAPPING, null);
        return mappings;
    }

    private static String url(PsiAnnotation classAnnotation, PsiAnnotation methodAnnotation) {
        // RequestMapping前缀
        String prefix = Optional.ofNullable(PsiAnnotationMemberValueUtil.getArrayFirstValue(classAnnotation, "value"))
                .map(String::valueOf).orElse("");
        // 肯定存在一个注解满足条件
        String suffix = Optional.ofNullable(PsiAnnotationMemberValueUtil.getArrayFirstValue(methodAnnotation, "value"))
                .map(String::valueOf).orElse("");
        if (!suffix.startsWith("/") && !prefix.endsWith("/")) {
            suffix = "/" + suffix;
        }
        return prefix + suffix;
    }

}
